package com.chrray.position.util.wx;

import com.alibaba.fastjson.JSONObject;
import com.chrray.position.util.result.ResponseResult;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.PrivateKey;

import static com.chrray.position.util.result.ResponseResults.fail;
import static com.chrray.position.util.result.ResponseResults.success;


/**
 * @author M
 * @date
 */
@Component
@Slf4j
public class PayUtils {
    /**
     * 商户id
     */
    String merchantId;

    /**
     * appid
     */
    String appid;
    /**
     * 私钥
     */
    String privateKey;
    /**
     * 回调地址
     */
    String notify_url;
    /**
     * API v3密钥
     */
    String apiV3Key;
    /**
     * 商户API证书的证书序列号
     */
    String merchantSerialNumber;
    /**
     * 退款地址
     */
    String refundNotifyUrl;

    public PayUtils(String merchantId, String appid, String privateKey, String notify_url, String apiV3Key, String merchantSerialNumber, String refundNotifyUrl) {
        this.merchantId = merchantId;
        this.appid = appid;
        this.privateKey = privateKey;
        this.notify_url = notify_url;
        this.apiV3Key = apiV3Key;
        this.merchantSerialNumber = merchantSerialNumber;
        this.refundNotifyUrl = refundNotifyUrl;
    }

    /**
     * 创建订单
     *
     * @param description  详情
     * @param out_trade_no 订单号
     * @param openId       openid
     * @param money        支付金额
     * @return
     * @throws IOException
     */

    public String createOrder(String description, String out_trade_no, String openId, Integer money, String timeExpire) throws IOException {

        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
                new ByteArrayInputStream(privateKey.getBytes("utf-8")));
        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(merchantId, new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)),
                apiV3Key.getBytes("utf-8"));

        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier));

        HttpClient httpClient = builder.build();
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectMapper objectMapper = new ObjectMapper();

        ObjectNode rootNode = objectMapper.createObjectNode();
        rootNode.put("mchid", merchantId)
                .put("appid", appid)
                .put("description", description)
                .put("notify_url", notify_url)
                .put("out_trade_no", out_trade_no)
                .put("time_expire", timeExpire);
        rootNode.putObject("amount")
                .put("total", money);
        rootNode.putObject("payer")
                .put("openid", openId);

        objectMapper.writeValue(bos, rootNode);

        httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
        CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(httpPost);

        String bodyAsString = EntityUtils.toString(response.getEntity());
        System.out.println(bodyAsString);
        JSONObject jsonObject = JSONObject.parseObject(bodyAsString);
        return jsonObject.getString("prepay_id");
    }

    /**
     * 退款
     *
     * @param transaction_id 原支付交易对应的微信订单号
     * @param out_refund_no  商户系统内部的退款单号，商户系统内部唯一，只能是数字、大小写字母_-|*@ ，同一退款单号多次请求只退一笔
     * @param out_trade_no   原支付交易对应的商户订单号
     * @param reason         退款原因
     * @param refundMoney    退款金额，
     * @param money          原支付交易的订单总金额
     * @return
     * @throws IOException
     */
    public ResponseResult refund(String transaction_id, String out_refund_no, String reason, String out_trade_no, Integer refundMoney, Integer money) {
        try {
            PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
                    new ByteArrayInputStream(privateKey.getBytes("utf-8")));
            AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                    new WechatPay2Credentials(merchantId, new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)),
                    apiV3Key.getBytes("utf-8"));

            WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                    .withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
                    .withValidator(new WechatPay2Validator(verifier));

            HttpClient httpClient = builder.build();
            HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds");
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type", "application/json; charset=utf-8");
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectMapper objectMapper = new ObjectMapper();

            ObjectNode rootNode = objectMapper.createObjectNode();
            rootNode.put("transaction_id", transaction_id)
                    .put("out_refund_no", out_refund_no)
                    .put("reason", reason)
                    .put("notify_url", refundNotifyUrl)
                    .put("funds_account", "AVAILABLE")
                    .put("out_trade_no", out_trade_no);
            rootNode.putObject("amount")
                    .put("refund", refundMoney)
                    .put("total", money)
                    .put("currency", "CNY");

            objectMapper.writeValue(bos, rootNode);

            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(httpPost);

            String bodyAsString = null;

            bodyAsString = EntityUtils.toString(response.getEntity());

            System.out.println(bodyAsString);
            JSONObject jsonObject = JSONObject.parseObject(bodyAsString);
            String status = jsonObject.getString("status");
            if(ObjectUtils.isEmpty(status)){
                return fail(bodyAsString);
            }
            if (jsonObject.getString("status").equals("SUCCESS") || jsonObject.getString("status").equals("PROCESSING")) {
                return success(jsonObject);
            } else {
                return fail(jsonObject);
            }

        } catch (IOException e) {
            e.printStackTrace();
            return fail();
        }
    }

}
